package org.xmap.app;

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

import org.xmap.debug.DebugStore;
import org.xmap.debug.DebugView;
import org.xmap.ui.Theme;
import org.xmap.ui.ViewManager;

/**
 * <p>应用程序类，基于Xmap的应用程序都应该从此派生，该类提供了各种抽象方法，派生类可以覆盖这些方法，来使得应用程序完整，这些方法包括appStart、appPause、appDestroy、showNotify、hideNotify、update、keyActive、pointerActive。</p>
 * <p>几个关键类的加载顺序为：Env->Theme->ViewManager->App。</p>
 * @author Zealot
 * @version 1.0
 */
public abstract class App extends MIDlet {

    /**
     * 全局的App实例，每一个应用有且只能有一个App实例，而且该实例是java虚拟机自动创建，使用者不允许自己创建。
     */
    public static App instance = null;

    /**
     * 通知系统，销毁当前应用程序。
     */
    public static final void destroy() {
        if (App.instance != null) {
            ViewManager.instance.debugStore("user destroy");
            ViewManager.instance.stop();
            if (Env.instance.debug) {
                DebugStore.instance.release();
            }
            App.instance.appDestroy();
            App.instance.notifyDestroyed();
            App.instance = null;
        }
    }

    /**
     * 构造函数，为App.instance赋值，并手动加载Env类、Theme类和ViewManager类，手动加载是为了避免一些不可预知的情况。
     */
    protected App() {
        App.instance = this;
        long t1 = System.currentTimeMillis();
        Env.instance.hashCode();
        Theme.instance.hashCode();
        ViewManager.instance.hashCode();
        int initInterval = (int) (System.currentTimeMillis() - t1);
        t1 = System.currentTimeMillis();
        if (Env.instance.debug) {
            DebugView.instance.hashCode();
            ViewManager.instance.debugPrint("load Env, Theme, ViewManager cost:" + initInterval + "ms");
            ViewManager.instance.debugPrint("init debug cost:" + (System.currentTimeMillis() - t1) + "ms");
            ViewManager.instance.debugPrint("topLine:" + Env.instance.topLine);
            ViewManager.instance.debugPrint("bottomLine:" + Env.instance.bottomLine);
            ViewManager.instance.debugPrint("defaultFontHeight:" + Env.instance.defaultFontHeight);
            ViewManager.instance.debugPrint("midpDefaultFontHeight:" + Env.instance.defaultFont.getHeight());
            t1 = System.currentTimeMillis();
            DebugStore.instance.hashCode(); // 读取持久存储的调试信息
            ViewManager.instance.debugPrint("load debug store cost:" + (System.currentTimeMillis() - t1) + "ms");
        }
    }

    /**
     * midp的startApp函数，派生自App的类不需要再覆盖这个函数，也不允许覆盖，该函数仅会在第一次被调用的时候调用appStart。
     */
    protected final void startApp() {
        if (!Env.instance.startAtFirstTime) {
            ViewManager.instance.start(this);
            Object o = ViewManager.instance.getDisplay().getCurrent();
            if (o == null) {
                ViewManager.instance.setView(ViewManager.instance);
            }
            this.appStart();
            Env.instance.startAtFirstTime = true;
        }
    }

    /**
     * midp的pauseApp函数，派生自App的类不需要再覆盖这个函数，也不允许覆盖，该函数会导致appPause函数被调用。
     */
    protected final void pauseApp() {
        this.appPause();
    }

    /**
     * midp的destroyApp函数，派生自App的类不需要再覆盖这个函数，也不允许覆盖，该函数会导致appDestroy函数被调用。
     * @param unconditional boolean 是否为强制关闭。
     * @throws MIDletStateChangeException 抛出异常。
     */
    protected final void destroyApp(boolean unconditional) throws MIDletStateChangeException {
        ViewManager.instance.debugStore("system destroy-" + unconditional);
        if (unconditional) {
            ViewManager.instance.stop();
            if (Env.instance.debug) {
                DebugStore.instance.release();
            }
            this.appDestroy();
            App.instance = null;
        } else {
            throw new MIDletStateChangeException();
        }
    }

    /**
     * 系统回调函数，在应用程序启动的时候被调用。
     */
    public void appStart() {
    }

    /**
     * 系统回调函数，在应用程序被暂停的时候被调用。
     */
    public void appPause() {
    }

    /**
     * 系统回调函数，在应用程序将要关闭的时候被调用。
     */
    public void appDestroy() {
    }

    /**
     * 系统回调函数，在程序被切换出去，或者低级界面被切换出去的时候被调用。
     */
    public void hideNotify() {
    }

    /**
     * 系统回调函数，在程序被重新切换到前台，或者低级界面被重新切换进来的时候被调用。
     */
    public void showNotify() {
    }

    /**
     * 系统回调函数，每个周期都会被回调。
     */
    public void update() {
    }

    /**
     * 系统回调函数，当有按键事件产生的时候就会被调用。
     */
    public void keyActive() {
    }

    /**
     * 系统回调函数，当有触笔事件产生的时候就会被调用。
     */
    public void pointerActive() {
    }
}
